package com.gitee.wsl.compose.chart.xy.bar.stack

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.gitee.wsl.compose.chart.KoalaPlotTheme
import com.gitee.wsl.compose.chart.xy.XYGraphScope
import com.gitee.wsl.compose.chart.xy.bar.BarComposable
import com.gitee.wsl.compose.chart.xy.bar.StackedBarSlate
import com.gitee.wsl.compose.chart.xy.bar.VerticalBarPlot
import com.gitee.wsl.compose.chart.xy.bar.stack.model.StackToBarEntryAdapter
import com.gitee.wsl.compose.chart.xy.bar.stack.model.BarStackedEntry
import com.gitee.wsl.compose.chart.xy.model.ListPointEntry

@Composable
fun <X, Y, E : ListPointEntry<X, Y>> XYGraphScope<X, Y>.StackedVerticalBarPlot(
    data: List<E>,
    offsetFun:(E)-> Y,
    bar: StackedBarSlate,
    barWidth: Float = 0.9f,
    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec
) = StackedVerticalBarPlot(
    data = data.map { BarStackedEntry(offsetFun(it),it) },
    bar = bar,
    barWidth = barWidth,
    animationSpec = animationSpec
)

/**
 * Composes a stacked vertical bar plot. This is a convenience method which defers to [VerticalBarPlot]. A stacked
 * bar plot can be also achieved by placing multiple [VerticalBarPlot]s on an
 * [io.github.koalaplot.core.xygraph.XYGraph], one for each "layer" of bars.
 *
 * @param data A List of BarPlotStackedPointEntry data points to plot.
 * @param bar A Composable function to render each bar. xIndex is the index into the data List, barIndex corresponds
 * to the index provided to [BarStackedEntry.y], and point is the data point from [data].
 */
@Composable
fun <X, Y, E : BarStackedEntry<X, Y>> XYGraphScope<X, Y>.StackedVerticalBarPlot(
    data: List<E>,
    modifier: Modifier = Modifier,
    bar: StackedBarSlate,
    barWidth: Float = 0.9f,
    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec
) {
    val maxBarCount = data.maxOf { it.y.size }

    for (barIndex in 0..<maxBarCount) {
        val layerData = StackToBarEntryAdapter(data, barIndex)
        VerticalBarPlot(
            layerData,
            modifier,
            { index ->
                bar(index, barIndex)
            },
            barWidth,
            animationSpec
        )
    }

}

/**
 * A Vertical Bar Plot to be used in an XYGraph and that plots multiple series as a stack of bars.
 *
 * @param X The type of the x-axis values
 * @param barWidth The fraction of space between adjacent x-axis bars may be used. Must be between 0 and 1,
 * defaults to 0.9.
 * @param content A block which describes the content for the plot.
 */
//@Composable
// fun <X> XYGraphScope<X, Float>.StackedVerticalBarPlot(
//    modifier: Modifier = Modifier,
//    barWidth: Float = 0.9f,
//    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec,
//    content: StackedVerticalBarPlotScope<X>.() -> Unit
//) {
//    val scope = remember(content) {
//        val scope = StackedVerticalBarPlotScopeImpl<X>()
//        scope.content()
//        scope
//    }
//
//    data class EntryWithBars<X>(
//        override val x: X,
//        val yb: List<Pair<Float, BarComposable>>
//    ) : BarStackedEntry<X, Float> {
//        override val yOrigin = 0f
//
//        override val y: List<Float> = object : AbstractList<Float>() {
//            override val size: Int = yb.size
//            override fun get(index: Int): Float = yb.subList(0, index + 1).fold(0F) { acc, (y, _) ->
//                acc + y
//            }
//        }
//    }
//
//    class DataHolder : AbstractList<BarStackedEntry<X, Float>>() {
//        val data: List<EntryWithBars<X>>
//
//        init {
//            val dataMap: MutableMap<X, EntryWithBars<X>> = mutableMapOf()
//            scope.series.forEach {
//                it.data.entries.forEach { (x, entry) ->
//                    val pos = dataMap.getOrPut(x) { EntryWithBars(x, listOf()) }
//                    dataMap[x] = pos.copy(yb = pos.yb + Pair(entry.first, entry.second))
//                }
//            }
//
//            data = dataMap.values.toList()
//        }
//
//        override val size: Int = data.size
//        override fun get(index: Int): BarStackedEntry<X, Float> {
//            return data[index]
//        }
//    }
//
//    val data = remember(scope) { DataHolder() }
//
//    StackedVerticalBarPlot(
//        data,
//        modifier,
//        { xIndex, seriesIndex ->
//            data.data[xIndex].yb[seriesIndex].second.invoke(this)
//        },
//        barWidth,
//        animationSpec
//    )
//}

